



import asyncio



'''
1. 按标签分类:
    使用 BinaryProtocol.decode_all 将内容分类，方便后续处理。
2. 流式处理:
    使用缓冲区支持分块读取，适配大数据或网络传输的场景。
3. 简单扩展:
    新增标签类型或自定义协议格式时，只需修改 BinaryProtocol 类，无需调整发送或接收逻辑。
'''

# 自定义协议：编码和解码数据
class BinaryProtocol:
    # @staticmethod
    def encode(label: str, content: bytes) -> bytes:
        """将标签和二进制数据编码"""
        label_bytes = label.encode('utf-8')  # 将标签转为字节
        label_len = len(label_bytes)        # 标签长度
        content_len = len(content)          # 内容长度
        # 打包：标签长度(4字节) + 标签内容 + 数据长度(4字节) + 数据内容
        return (
            label_len.to_bytes(4, 'big') +
            label_bytes +
            content_len.to_bytes(4, 'big') +
            content
        )

    # @staticmethod
    def decode_all(data: bytes) -> dict:
        """从二进制数据中解析出标签和内容，返回按标签分类的内容列表"""
        results = {}
        offset = 0
        while offset < len(data):
            # 读取标签长度
            label_len = int.from_bytes(data[offset:offset + 4], 'big')
            offset += 4

            # 读取标签内容
            label = data[offset:offset + label_len].decode('utf-8')
            offset += label_len

            # 读取数据长度
            content_len = int.from_bytes(data[offset:offset + 4], 'big')
            offset += 4

            # 读取数据内容
            content = data[offset:offset + content_len]
            offset += content_len

            # 将数据按标签分类
            if label not in results:
                results[label] = []
            results[label].append(content)
        
        return results

# 模拟发送端
async def sender(writer: asyncio.StreamWriter):
    messages = [
        ("TEXT", b"Hello, World!"),
        ("IMAGE", b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR"),
        ("TEXT", b"Another message"),
        ("BINARY", b"\x00\x01\x02\x03\x04")
    ]

    for label, content in messages:
        # 编码带标签的二进制数据
        encoded_message = BinaryProtocol.encode(label, content)
        print(f"发送数据 - 标签: {label}, 数据长度: {len(content)}")
        writer.write(encoded_message)  # 发送数据
        await writer.drain()
        await asyncio.sleep(1)  # 模拟延迟

    writer.close()
    await writer.wait_closed()

# 接收端
async def receiver(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
    buffer = b""
    while True:
        try:
            # 读取数据块
            chunk = await reader.read(1024)  # 读取 1024 字节数据块
            if not chunk:
                break
            buffer += chunk

            # 解析缓冲区中的数据
            decoded_results = BinaryProtocol.decode_all(buffer)

            # 打印解析结果
            for label, contents in decoded_results.items():
                for content in contents:
                    print(f"接收到数据 - 标签: {label}, 内容: {content}")

            # 清空缓冲区（假设数据已完全解析）
            buffer = b""
        except asyncio.IncompleteReadError:
            print("连接已关闭")
            break

# 主程序
async def main():
    # 创建服务器
    server = await asyncio.start_server(receiver, '127.0.0.1', 8888)
    addr = server.sockets[0].getsockname()
    print(f"服务器已启动，监听 {addr}")

    # 创建客户端连接服务器
    reader, writer = await asyncio.open_connection('127.0.0.1', 8888)
    # 启动发送任务
    await sender(writer)

    server.close()
    await server.wait_closed()

# 运行程序
if __name__ == "__main__":
    asyncio.run(main())
